#ifndef parser_h__
#define parser_h__

#include <string>
#include <map>
#include <algorithm>
#include <iostream>
#include <list>

#include "tokenizer.h"
#include "basicparser.h"
#include "symbolstable.h"
#include "utills.h"

namespace CCompiler 
{
    SymType *getExistingTypeOrInsert(SymType *type, SymTable& tbl);

	class ParserWithSymTable: public BasicParser
	{
		SymTable globalTable_; // global table
        SymTableStack stack;
		typedef std::pair<SymType*, std::string> TypeAndName;
		typedef std::vector<TypeAndName> TypesAndNames;
        
        enum getNamesAndTypesMode { gntmOnlyTypes, gntmFunctionLike, gntmVariables };
        void getNamesAndTypes(TypesAndNames &lst, getNamesAndTypesMode mode);
        TypeAndName getSingleNameAndType(SymType *baseType, getNamesAndTypesMode mode);
		TypeAndName getFunctionParameter();

        //SymType *getExistingTypeOrInsert(SymType *type);

        std::string getName(getNamesAndTypesMode mode);

        void parseVariablesOrFunctionDefinition(SymTableInterface &tbl, bool disableFunctions = false);
        void parseStructures(SymTableInterface &tbl);
        void parseTypedefs(SymTableInterface &tbl);
        SynStatementBlock *parseStatementBlock();
        SymTypeStruct *extractTypeStruct(SymTableInterface &tbl);
        void getVariables(TypesAndNames &lst, SymType* baseType);
        template <class T> void insertIntoTable(SymTableInterface &tbl, TypesAndNames &varLst)
        {
            if(getTokenType() != ttSemicolon) throw Errors::SyntaxError("Missing semicolon", tok_);
            for(size_t i = 0; i < varLst.size(); ++i)
            {
                if(tbl.getClosestTable().exists(varLst[i].second)) throw Errors::SyntaxError("Name redefinition", tok_);
                tbl.insert(new T(varLst[i].first, varLst[i].second));                
            }
            nextToken();  
        }


		bool isExistingType(Token &tok);
		bool isExistingName(Token &tok);

        SynExpression *parseFunction(SynExpression *expr);
        SynExpression *parseArray(SynExpression *expr);
        SynExpression *parseStruct(SynExpression *expr);
        SynExpression *parsePointerOnStruct(SynExpression *expr);

        virtual SynExpression *internalParseExpression(Int2Type<lowest_level>);
        SynExpression *parseUnaryExpression();
        SynExpression *parsePostfixExpression();
        SynExpression *parsePrimaryExpression();
        SynExpression *parseAssignmentExpression();


        //SynNode *
	public:
		virtual SynExpression *parseIdentifier();
        ParserWithSymTable(Tokenizer &tokenizer): BasicParser(tokenizer), stack(&globalTable_) 
        {
            globalTable_.insert(new SymTypeInt());
            globalTable_.insert(new SymTypeFloat());
            globalTable_.insert(new SymTypeVoid());
            globalTable_.insert(new SymTypeChar());
            globalTable_.insert(new SymTypePointer((SymType *) globalTable_.find("char"), "char*"));
        }
		void print(std::ostream &stream)
		{
			globalTable_.print(stream);
		}
		SynNode *parse();
        SynExpression *parseExpression();
	};

}

#endif // parser_h__